package com.rizzo.web.breadcrumb;

import com.rizzo.web.util.MessageUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.definition.StateDefinition;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;

import java.util.LinkedList;

/**
 * Listener to handle breadcrumb navigation. It works as follows:
 *  - If one enters a view-state the id of the view-state is used as resourceBundle-key to lookup it meaningful name,
 *      and added to the Breadcrumb-trail (a LinkedList).
 *  - If one enters a sub-flow from an active flow that view-state-id is added to the Breadcrumb-trail.
 */
public class BreadcrumbFlowExecutionListener extends FlowExecutionListenerAdapter {

    /** Field LOGGER  */
    private static final Logger LOGGER = LoggerFactory.getLogger(BreadcrumbFlowExecutionListener.class);

    /** Field CONTEXT_KEY  */
    private static final String CONTEXT_KEY = "trail";

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) {
        FlowDefinition flowDefinition = session.getDefinition();
        LOGGER.debug("Starting session for: " + flowDefinition.getId());
        // new flow session is initiated, so store trail in context
        LinkedList<Breadcrumb> trail = (LinkedList<Breadcrumb>) context.getConversationScope().get(CONTEXT_KEY);
        if (trail == null) {
            trail = new LinkedList<Breadcrumb>();
            context.getConversationScope().put(CONTEXT_KEY, trail);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public void stateEntering(RequestContext context, StateDefinition state) {
        LOGGER.debug("Entering state: " + state.getId());
        LinkedList<Breadcrumb> trail = (LinkedList<Breadcrumb>) context.getConversationScope().get(CONTEXT_KEY);
        // only add them when they are of the type ViewState
        if (state instanceof ViewState) {
            if (trail != null) {
                // create new breadcrumb
                Breadcrumb breadcrumb = new Breadcrumb(trail.size(), state.getId(), MessageUtil.resolveFlowMessage(state.getId()));
                if (trail.contains(breadcrumb)) {
                    // breadcrumb already exists in trail and erase succeeding breadcrumbs
                    int pos = trail.indexOf(breadcrumb);
                    trail.subList(pos + 1, trail.size()).clear();
                    LOGGER.debug("Breadcrumbs erased successfully");
                } else {
                    // add new breadscrumb to trail
                    trail.add(breadcrumb);
                    LOGGER.debug("Breadcrumb added to trail");
                }
            } else {
                LOGGER.error("Breadcrumb trail not found in context");
            }
        } else if (state instanceof EndState) {
            // pop of the last breadcrumb of the trail
            trail.removeLast();
            LOGGER.debug("Removed last added breadcrumb");
        }
    }

}
